package websocket

import (
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/olahol/melody"
)

// Service 使用 Melody 的 WebSocket 服务（极简版）
type Service struct {
	melody *melody.Melody
	mu     sync.RWMutex

	// 用户映射（用户ID -> Sessions）
	userSessions map[string][]*melody.Session

	// 房间映射（房间名 -> Sessions）
	roomSessions map[string][]*melody.Session
}

var (
	instance *Service
	once     sync.Once
)

// GetService 获取 WebSocket 服务单例
func GetService() *Service {
	once.Do(func() {
		instance = NewService()
	})
	return instance
}

// NewService 创建新的 WebSocket 服务
func NewService() *Service {
	m := melody.New()

	// 配置
	m.Config.WriteWait = 10 * time.Second
	m.Config.PongWait = 60 * time.Second
	m.Config.PingPeriod = 54 * time.Second
	m.Config.MaxMessageSize = 512000 // 500KB
	m.Config.MessageBufferSize = 256

	s := &Service{
		melody:       m,
		userSessions: make(map[string][]*melody.Session),
		roomSessions: make(map[string][]*melody.Session),
	}

	// 设置事件处理器
	s.setupHandlers()

	return s
}

// setupHandlers 设置事件处理器
func (s *Service) setupHandlers() {
	// 连接事件
	s.melody.HandleConnect(func(session *melody.Session) {
		userID, _ := session.Get("user_id")
		if userID != nil {
			s.addUserSession(userID.(string), session)
		}

		// 发送欢迎消息
		welcome := map[string]interface{}{
			"type":    "welcome",
			"message": "连接成功",
			"time":    time.Now().Format("2006-01-02 15:04:05"),
		}
		data, _ := json.Marshal(welcome)
		session.Write(data)
	})

	// 断开连接事件
	s.melody.HandleDisconnect(func(session *melody.Session) {
		userID, exists := session.Get("user_id")
		if exists && userID != nil {
			s.removeUserSession(userID.(string), session)
		}

		room, exists := session.Get("room")
		if exists && room != nil {
			s.removeRoomSession(room.(string), session)
		}
	})

	// 消息处理
	s.melody.HandleMessage(func(session *melody.Session, msg []byte) {
		// 解析消息
		var message map[string]interface{}
		if err := json.Unmarshal(msg, &message); err != nil {
			s.sendError(session, "消息格式错误")
			return
		}

		// 根据类型处理
		msgType, _ := message["type"].(string)
		switch msgType {
		case "join_room":
			s.handleJoinRoom(session, message)
		case "leave_room":
			s.handleLeaveRoom(session, message)
		case "room_message":
			s.handleRoomMessage(session, message)
		case "private_message":
			s.handlePrivateMessage(session, message)
		case "broadcast":
			s.handleBroadcast(session, message)
		default:
			// 默认echo回去
			session.Write(msg)
		}
	})

	// 错误处理
	s.melody.HandleError(func(session *melody.Session, err error) {
		userID, _ := session.Get("user_id")
		fmt.Printf("WebSocket错误 - user: %v, error: %v\n", userID, err)
	})
}

// HandleGinUpgrade 处理 Gin 的 WebSocket 升级
func (s *Service) HandleGinUpgrade(c *gin.Context) {
	// 获取用户信息
	userID := c.Query("user_id")
	if userID == "" {
		userID = fmt.Sprintf("anonymous_%d", time.Now().Unix())
	}

	// 处理升级
	err := s.melody.HandleRequestWithKeys(c.Writer, c.Request, map[string]interface{}{
		"user_id":    userID,
		"ip":         c.ClientIP(),
		"user_agent": c.Request.UserAgent(),
	})

	if err != nil {
		fmt.Printf("WebSocket升级失败: %v\n", err)
	}
}

// 房间管理
func (s *Service) handleJoinRoom(session *melody.Session, message map[string]interface{}) {
	room, ok := message["room"].(string)
	if !ok {
		s.sendError(session, "房间名称无效")
		return
	}

	// 离开旧房间
	if oldRoom, exists := session.Get("room"); exists && oldRoom != nil {
		s.removeRoomSession(oldRoom.(string), session)
	}

	// 加入新房间
	session.Set("room", room)
	s.addRoomSession(room, session)

	// 通知加入成功
	response := map[string]interface{}{
		"type":    "room_joined",
		"room":    room,
		"message": fmt.Sprintf("已加入房间: %s", room),
	}
	data, _ := json.Marshal(response)
	session.Write(data)

	// 通知房间其他人
	userID, _ := session.Get("user_id")
	s.ToRoom(room).SendExcept(session, "room_notification", map[string]interface{}{
		"message": fmt.Sprintf("用户 %v 加入了房间", userID),
	})
}

func (s *Service) handleLeaveRoom(session *melody.Session, message map[string]interface{}) {
	room, exists := session.Get("room")
	if !exists || room == nil {
		return
	}

	roomStr := room.(string)
	s.removeRoomSession(roomStr, session)
	session.UnSet("room")

	// 通知房间其他人
	userID, _ := session.Get("user_id")
	s.ToRoom(roomStr).Send("room_notification", map[string]interface{}{
		"message": fmt.Sprintf("用户 %v 离开了房间", userID),
	})
}

func (s *Service) handleRoomMessage(session *melody.Session, message map[string]interface{}) {
	room, exists := session.Get("room")
	if !exists || room == nil {
		s.sendError(session, "您还未加入任何房间")
		return
	}

	userID, _ := session.Get("user_id")
	// 发送给房间所有人
	s.ToRoom(room.(string)).Send("room_message", map[string]interface{}{
		"from":    userID,
		"message": message["data"],
		"time":    time.Now().Format("15:04:05"),
	})
}

func (s *Service) handlePrivateMessage(session *melody.Session, message map[string]interface{}) {
	toUserID, ok := message["to"].(string)
	if !ok {
		s.sendError(session, "目标用户ID无效")
		return
	}

	userID, _ := session.Get("user_id")
	// 发送私聊消息
	s.ToUser(toUserID).Send("private_message", map[string]interface{}{
		"from":    userID,
		"message": message["data"],
		"time":    time.Now().Format("15:04:05"),
	})
}

func (s *Service) handleBroadcast(session *melody.Session, message map[string]interface{}) {
	userID, _ := session.Get("user_id")
	// 广播给所有人
	s.ToAll().Send("broadcast", map[string]interface{}{
		"from":    userID,
		"message": message["data"],
		"time":    time.Now().Format("15:04:05"),
	})
}

// 发送错误消息
func (s *Service) sendError(session *melody.Session, err string) {
	response := map[string]interface{}{
		"type":  "error",
		"error": err,
	}
	data, _ := json.Marshal(response)
	session.Write(data)
}

// 用户会话管理
func (s *Service) addUserSession(userID string, session *melody.Session) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.userSessions[userID] = append(s.userSessions[userID], session)
}

func (s *Service) removeUserSession(userID string, session *melody.Session) {
	s.mu.Lock()
	defer s.mu.Unlock()

	sessions := s.userSessions[userID]
	for i, sess := range sessions {
		if sess == session {
			s.userSessions[userID] = append(sessions[:i], sessions[i+1:]...)
			break
		}
	}

	if len(s.userSessions[userID]) == 0 {
		delete(s.userSessions, userID)
	}
}

// 房间会话管理
func (s *Service) addRoomSession(room string, session *melody.Session) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.roomSessions[room] = append(s.roomSessions[room], session)
}

func (s *Service) removeRoomSession(room string, session *melody.Session) {
	s.mu.Lock()
	defer s.mu.Unlock()

	sessions := s.roomSessions[room]
	for i, sess := range sessions {
		if sess == session {
			s.roomSessions[room] = append(sessions[:i], sessions[i+1:]...)
			break
		}
	}

	if len(s.roomSessions[room]) == 0 {
		delete(s.roomSessions, room)
	}
}

// Broadcaster 广播器接口
type Broadcaster struct {
	service *Service
	filter  func(*melody.Session) bool
}

// Send 发送消息
func (b *Broadcaster) Send(event string, data interface{}) error {
	message := map[string]interface{}{
		"type": event,
		"data": data,
		"time": time.Now().Unix(),
	}

	msgBytes, err := json.Marshal(message)
	if err != nil {
		return err
	}

	return b.service.melody.BroadcastFilter(msgBytes, b.filter)
}

// SendExcept 发送消息（排除某个session）
func (b *Broadcaster) SendExcept(except *melody.Session, event string, data interface{}) error {
	message := map[string]interface{}{
		"type": event,
		"data": data,
		"time": time.Now().Unix(),
	}

	msgBytes, err := json.Marshal(message)
	if err != nil {
		return err
	}

	return b.service.melody.BroadcastFilter(msgBytes, func(s *melody.Session) bool {
		return s != except && b.filter(s)
	})
}

// ToAll 广播给所有人
func (s *Service) ToAll() *Broadcaster {
	return &Broadcaster{
		service: s,
		filter:  func(s *melody.Session) bool { return true },
	}
}

// ToUser 发送给指定用户
func (s *Service) ToUser(userID string) *Broadcaster {
	return &Broadcaster{
		service: s,
		filter: func(session *melody.Session) bool {
			uid, exists := session.Get("user_id")
			return exists && uid == userID
		},
	}
}

// ToRoom 发送给房间
func (s *Service) ToRoom(room string) *Broadcaster {
	return &Broadcaster{
		service: s,
		filter: func(session *melody.Session) bool {
			r, exists := session.Get("room")
			return exists && r == room
		},
	}
}

// ToUsers 发送给多个用户
func (s *Service) ToUsers(userIDs []string) *Broadcaster {
	userMap := make(map[string]bool)
	for _, id := range userIDs {
		userMap[id] = true
	}

	return &Broadcaster{
		service: s,
		filter: func(session *melody.Session) bool {
			uid, exists := session.Get("user_id")
			if !exists || uid == nil {
				return false
			}
			return userMap[uid.(string)]
		},
	}
}

// GetStats 获取统计信息
func (s *Service) GetStats() map[string]interface{} {
	s.mu.RLock()
	defer s.mu.RUnlock()

	totalConnections := 0
	for _, sessions := range s.userSessions {
		totalConnections += len(sessions)
	}

	return map[string]interface{}{
		"total_connections": totalConnections,
		"total_users":       len(s.userSessions),
		"total_rooms":       len(s.roomSessions),
	}
}
